ot-builtin-commit.c: add --skip-list option
authorJonathan Lebon <jlebon@redhat.com>
Fri, 22 Apr 2016 16:35:48 +0000 (12:35 -0400)
committerColin Walters (automation) <walters+githubbot@verbum.org>
Fri, 6 May 2016 14:44:55 +0000 (14:44 +0000)
This was already supported by the commit modifier API, just needed to
expose it. This will also be used to test the libarchive API in a future
test.

Closes: #275
Approved by: cgwalters

Makefile-tests.am
man/ostree-commit.xml
src/ostree/ot-builtin-commit.c
tests/basic-test.sh
tests/test-setuid.sh [deleted file]

index 4986b427c20b58616da75e37095594af33e91f31..bb1cee41c6b3e370d046104128f04a329afcdb86 100644 (file)
@@ -72,7 +72,6 @@ test_scripts = \
        tests/test-repo-checkout-subpath.sh     \
        tests/test-reset-nonlinear.sh \
        tests/test-oldstyle-partial.sh \
-       tests/test-setuid.sh \
        tests/test-delta.sh \
        tests/test-xattrs.sh \
        tests/test-auto-summary.sh \
index 4a86c1d2cc6c00bfad4ef63e838c38e2aa4c0947..c4842584562845a74e7f4d9aaeed862471d5c75c 100644 (file)
@@ -163,7 +163,15 @@ Boston, MA 02111-1307, USA.
                 <term><option>--statoverride</option>="PATH"</term>
 
                 <listitem><para>
-                    File containing list of modifications to make permissions.
+                    File containing list of modifications to make permissions (file mode, followed by space, followed by file path).
+                </para></listitem>
+            </varlistentry>
+
+            <varlistentry>
+                <term><option>--skip-list</option>="PATH"</term>
+
+                <listitem><para>
+                    File containing list of file paths to skip (one path per line).
                 </para></listitem>
             </varlistentry>
 
index 1d96855de37141c77464ea4970fdc85ce14bc6a2..a021fbfa470545f67cf53dfa4bbcd6424e87a307 100644 (file)
@@ -36,6 +36,7 @@ static char *opt_parent;
 static gboolean opt_orphan;
 static char *opt_branch;
 static char *opt_statoverride_file;
+static char *opt_skiplist_file;
 static char **opt_metadata_strings;
 static char **opt_detached_metadata_strings;
 static gboolean opt_link_checkout_speedup;
@@ -84,6 +85,7 @@ static GOptionEntry options[] = {
   { "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &opt_tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL },
   { "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &opt_skip_if_unchanged, "If the contents are unchanged from previous commit, do nothing", NULL },
   { "statoverride", 0, 0, G_OPTION_ARG_FILENAME, &opt_statoverride_file, "File containing list of modifications to make to permissions", "PATH" },
+  { "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" },
   { "table-output", 0, 0, G_OPTION_ARG_NONE, &opt_table_output, "Output more information in a KEY: VALUE format", NULL },
   { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"},
   { "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
@@ -95,65 +97,85 @@ static GOptionEntry options[] = {
 };
 
 static gboolean
-parse_statoverride_file (GHashTable   **out_mode_add,
-                         GCancellable  *cancellable,
-                         GError        **error)
+parse_file_by_line (const char    *path,
+                    gboolean     (*cb)(const char*, void*, GError**),
+                    void          *cbdata,
+                    GCancellable  *cancellable,
+                    GError       **error)
 {
   gboolean ret = FALSE;
-  gsize len;
-  char **iter = NULL; /* nofree */
-  g_autoptr(GHashTable) ret_hash = NULL;
-  g_autoptr(GFile) path = NULL;
   g_autofree char *contents = NULL;
+  g_autoptr(GFile) file = NULL;
   char **lines = NULL;
 
-  path = g_file_new_for_path (opt_statoverride_file);
-
-  if (!g_file_load_contents (path, cancellable, &contents, &len, NULL,
-                             error))
+  file = g_file_new_for_path (path);
+  if (!g_file_load_contents (file, cancellable, &contents, NULL, NULL, error))
     goto out;
-  
-  ret_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-  lines = g_strsplit (contents, "\n", -1);
 
-  for (iter = lines; iter && *iter; iter++)
+  lines = g_strsplit (contents, "\n", -1);
+  for (char **iter = lines; iter && *iter; iter++)
     {
-      const char *line = *iter;
-
-      if (*line == '+')
-        {
-          const char *spc;
-          guint mode_add;
+      /* skip empty lines at least */
+      if (**iter == '\0')
+        continue;
 
-          spc = strchr (line + 1, ' ');
-          if (!spc)
-            {
-              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                           "Malformed statoverride file");
-              goto out;
-            }
-          
-          mode_add = (guint32)(gint32)g_ascii_strtod (line + 1, NULL);
-          g_hash_table_insert (ret_hash,
-                               g_strdup (spc + 1),
-                               GUINT_TO_POINTER((gint32)mode_add));
-        }
+      if (!cb (*iter, cbdata, error))
+        goto out;
     }
 
   ret = TRUE;
-  ot_transfer_out_value (out_mode_add, &ret_hash);
- out:
+out:
   g_strfreev (lines);
   return ret;
 }
 
+static gboolean
+handle_statoverride_line (const char  *line,
+                          void        *data,
+                          GError     **error)
+{
+  GHashTable *files = data;
+  const char *spc;
+  guint mode_add;
+
+  spc = strchr (line, ' ');
+  if (spc == NULL)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Malformed statoverride file (no space found)");
+      return FALSE;
+    }
+
+  mode_add = (guint32)(gint32)g_ascii_strtod (line, NULL);
+  g_hash_table_insert (files, g_strdup (spc + 1),
+                       GUINT_TO_POINTER((gint32)mode_add));
+  return TRUE;
+}
+
+static gboolean
+handle_skiplist_line (const char  *line,
+                      void        *data,
+                      GError     **error)
+{
+  GHashTable *files = data;
+  g_hash_table_add (files, g_strdup (line));
+  return TRUE;
+}
+
+struct CommitFilterData {
+  GHashTable *mode_adds;
+  GHashTable *skip_list;
+};
+
 static OstreeRepoCommitFilterResult
 commit_filter (OstreeRepo         *self,
                const char         *path,
                GFileInfo          *file_info,
                gpointer            user_data)
 {
-  GHashTable *mode_adds = user_data;
+  struct CommitFilterData *data = user_data;
+  GHashTable *mode_adds = data->mode_adds;
+  GHashTable *skip_list = data->skip_list;
   gpointer value;
 
   if (opt_owner_uid >= 0)
@@ -169,7 +191,13 @@ commit_filter (OstreeRepo         *self,
                                         current_mode | mode_add);
       g_hash_table_remove (mode_adds, path);
     }
-  
+
+  if (skip_list && g_hash_table_contains (skip_list, path))
+    {
+      g_hash_table_remove (skip_list, path);
+      return OSTREE_REPO_COMMIT_FILTER_SKIP;
+    }
+
   return OSTREE_REPO_COMMIT_FILTER_ALLOW;
 }
 
@@ -310,9 +338,11 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError
   glnx_unref_object OstreeMutableTree *mtree = NULL;
   g_autofree char *tree_type = NULL;
   g_autoptr(GHashTable) mode_adds = NULL;
+  g_autoptr(GHashTable) skip_list = NULL;
   OstreeRepoCommitModifierFlags flags = 0;
   OstreeRepoCommitModifier *modifier = NULL;
   OstreeRepoTransactionStats stats;
+  struct CommitFilterData filter_data = { 0, };
 
   context = g_option_context_new ("[PATH] - Commit a new revision");
 
@@ -324,7 +354,17 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError
 
   if (opt_statoverride_file)
     {
-      if (!parse_statoverride_file (&mode_adds, cancellable, error))
+      mode_adds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+      if (!parse_file_by_line (opt_statoverride_file, handle_statoverride_line,
+                               mode_adds, cancellable, error))
+        goto out;
+    }
+
+  if (opt_skiplist_file)
+    {
+      skip_list = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+      if (!parse_file_by_line (opt_skiplist_file, handle_skiplist_line,
+                               skip_list, cancellable, error))
         goto out;
     }
 
@@ -359,9 +399,13 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError
       || opt_owner_uid >= 0
       || opt_owner_gid >= 0
       || opt_statoverride_file != NULL
+      || opt_skiplist_file != NULL
       || opt_no_xattrs)
     {
-      modifier = ostree_repo_commit_modifier_new (flags, commit_filter, mode_adds, NULL);
+      filter_data.mode_adds = mode_adds;
+      filter_data.skip_list = skip_list;
+      modifier = ostree_repo_commit_modifier_new (flags, commit_filter,
+                                                  &filter_data, NULL);
     }
 
   if (opt_parent)
@@ -491,6 +535,22 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError
       goto out;
     }
 
+  if (skip_list && g_hash_table_size (skip_list) > 0)
+    {
+      GHashTableIter hash_iter;
+      gpointer key;
+
+      g_hash_table_iter_init (&hash_iter, skip_list);
+
+      while (g_hash_table_iter_next (&hash_iter, &key, NULL))
+        {
+          g_printerr ("Unmatched skip-list path: %s\n", (char*)key);
+        }
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Unmatched skip-list paths");
+      goto out;
+    }
+
   if (!ostree_repo_write_mtree (repo, mtree, &root, cancellable, error))
     goto out;
 
index b24779555b81e4bc7df85941a211bcf2135849b7..a44ee630591dcbdd5c00c93ccbf7549e43f72c31 100755 (executable)
@@ -19,7 +19,7 @@
 
 set -euo pipefail
 
-echo "1..54"
+echo "1..55"
 
 $OSTREE checkout test2 checkout-test2
 echo "ok checkout"
@@ -179,13 +179,31 @@ cd ${test_tmpdir}/checkout-test2-4
 $OSTREE commit -b test2 -s "no xattrs" --no-xattrs
 echo "ok commit with no xattrs"
 
+# NB: The + is optional, but we need to make sure we support it
 cd ${test_tmpdir}
 cat > test-statoverride.txt <<EOF
-+2048 /a/nested/3
++1048 /a/nested/2
+2048 /a/nested/3
 EOF
 cd ${test_tmpdir}/checkout-test2-4
-$OSTREE commit -b test2 -s "with statoverride" --statoverride=../test-statoverride.txt
-echo "ok commit statoverridde"
+$OSTREE commit -b test2-override -s "with statoverride" --statoverride=../test-statoverride.txt
+cd ${test_tmpdir}
+$OSTREE checkout test2-override checkout-test2-override
+test -g checkout-test2-override/a/nested/2
+test -u checkout-test2-override/a/nested/3
+echo "ok commit statoverride"
+
+cd ${test_tmpdir}
+cat > test-skiplist.txt <<EOF
+/a/nested/3
+EOF
+cd ${test_tmpdir}/checkout-test2-4
+assert_has_file a/nested/3
+$OSTREE commit -b test2-skiplist -s "with skiplist" --skip-list=../test-skiplist.txt
+cd ${test_tmpdir}
+$OSTREE checkout test2-skiplist checkout-test2-skiplist
+assert_not_has_file checkout-test2-skiplist/a/nested/3
+echo "ok commit skiplist"
 
 cd ${test_tmpdir}
 $OSTREE prune
diff --git a/tests/test-setuid.sh b/tests/test-setuid.sh
deleted file mode 100755 (executable)
index edf707d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2013 Colin Walters <walters@verbum.org>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
-set -euo pipefail
-
-echo "1..1"
-
-. $(dirname $0)/libtest.sh
-
-setup_test_repository "bare"
-
-cd ${test_tmpdir}
-cat > test-statoverride.txt <<EOF
-+2048 /abinary
-EOF
-$OSTREE checkout test2 test2-checkout
-touch test2-checkout/abinary
-chmod a+x test2-checkout/abinary
-(cd test2-checkout && $OSTREE commit -b test2 -s "with statoverride" --statoverride=../test-statoverride.txt)
-rm -rf test2-checkout
-$OSTREE checkout test2 test2-checkout
-test -u test2-checkout/abinary
-
-echo "ok"